package com.efrei.schoolmanager.views;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.swing.BoxLayout;
import javax.swing.GroupLayout;
import javax.swing.GroupLayout.Alignment;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import org.hibernate.HibernateException;

import com.efrei.schoolmanager.controlers.ControleurClasse;
import com.efrei.schoolmanager.model.ModeleListeMatieres;
import com.efrei.schoolmanager.model.obj.Classe;
import com.efrei.schoolmanager.model.obj.Enseignant;
import com.efrei.schoolmanager.model.obj.Matiere;
import com.efrei.schoolmanager.tools.Tools;
import com.efrei.schoolmanager.views.components.CustomButton;
import com.efrei.schoolmanager.views.components.CustomTextField;

public class VueEditerMatieres extends JDialog {
	private static final long serialVersionUID = -2627884879559027806L;

	private final static String TITLE = "Editer les matieres d'une classe";

	private final VueEditerMatieres vueActuelle;
	// Controleur
	private final ControleurClasse controleur;

	/* Panels */
	private JPanel mainPanel, titlePanel, matieresClassePanel, middlePanel,
			matieresGeneralesPanel, validationPanel, classePanel, centerPanel;
	/* Labels */
	private JLabel titleLabel, classeLabel, matieresClasseLabel,
			matieresGeneralesLabel;
	/* Zones de textes mono-ligne */
	private CustomTextField classeTextField;

	/* Boutons */
	private CustomButton ajouterMatiereButton, retirerMatiereButton,
			validerButton;

	/* Listes */
	private JList matieresClasseList, matieresGeneralesList;
	private JScrollPane matieresClasseScroll, matieresGeneralesScroll;

	/* Listes déroulantes */
	private JComboBox profEnseignantComboBox;

	/* Classe a modifier */
	private final Classe currentClasse;

	public VueEditerMatieres(VueListerClasse proprio,
			ControleurClasse controleur) {
		super(proprio.getFrame(), TITLE, true);
		this.controleur = controleur;
		vueActuelle = this;
		this.addWindowListener(new QuitterDialogListener());
		currentClasse = controleur.getCurrentClasse();
		/* Composants */
		initLabels();
		initTextFields();
		initButtons();
		initList();
		initComboBox();
		remplirTitlePanel();
		remplirMiddlePanel();
		remplirClassePanel();
		remplirValidationPanel();
		remplirMatiereClassePanel();
		remplirMatieresGeneralesPanel();
		remplirCenterPanel();
		remplirMainPanel();

		/* Panel principal */
		initContentPane();

		/* Frame */
		configurerVue();
	}

	public void showDialog() {
		setVisible(true);
	}

	private void configurerVue() {
		pack();
		this.setLocationRelativeTo(null);
		this.showDialog();
	}

	private void initContentPane() {
		setLayout(new BorderLayout());
		add(mainPanel, BorderLayout.CENTER);
		add(titlePanel, BorderLayout.NORTH);
	}

	private void initLabels() {
		titleLabel = new JLabel(TITLE);
		titleLabel.setFont(new Font("Arial", Font.BOLD, 20));
		classeLabel = new JLabel("Classe:");
		matieresGeneralesLabel = new JLabel("Matieres disponibles");
		matieresClasseLabel = new JLabel("Matieres de la classe");
	}

	private void initTextFields() {
		/* Text fields */
		classeTextField = new CustomTextField(currentClasse.toString(),
				new Dimension(180, 25));
		classeTextField.setEditable(false);

	}

	private void initButtons() {
		/* Listeners */
		AjouterMatiereButtonListener ajouterMatiereListener = new AjouterMatiereButtonListener();
		RetirerMatiereButtonListener retirerMatiereListener = new RetirerMatiereButtonListener();
		ValiderButtonListener validerListener = new ValiderButtonListener();
		ajouterMatiereButton = new CustomButton("Ajouter matiere");
		ajouterMatiereButton.addActionListener(ajouterMatiereListener);
		ajouterMatiereButton.setEnabled(false);
		retirerMatiereButton = new CustomButton("Retirer matiere");
		retirerMatiereButton.addActionListener(retirerMatiereListener);
		retirerMatiereButton.setEnabled(false);
		validerButton = new CustomButton("Valider");
		validerButton.addActionListener(validerListener);
	}

	private void initList() {
		MatieresClasseListListener matieresClasseListener = new MatieresClasseListListener();
		MatieresGeneralesListListener matieresGeneralesListener = new MatieresGeneralesListListener();
		matieresClasseList = new JList(new ModeleListeMatieres());
		matieresGeneralesList = new JList(new ModeleListeMatieres());
		matieresClasseScroll = new JScrollPane(matieresClasseList);
		matieresGeneralesScroll = new JScrollPane(matieresGeneralesList);
		// Ajout des listeners
		matieresClasseList.addListSelectionListener(matieresClasseListener);
		matieresGeneralesList
				.addListSelectionListener(matieresGeneralesListener);

		/* Recuperer matieres */
		Set<Matiere> matieresClasse = currentClasse.getMatieres();
		List<Matiere> matieresGenerales = controleur.getMatieres();
		/* Recuperer les modeles */
		ModeleListeMatieres modeleMatieresClasse = (ModeleListeMatieres) matieresClasseList
				.getModel();
		ModeleListeMatieres modeleMatieresGenerales = (ModeleListeMatieres) matieresGeneralesList
				.getModel();
		/* Remplir les listes */
		// Matieres de la classe
		for (Matiere matiereClasse : matieresClasse) {
			modeleMatieresClasse.addMatiere(matiereClasse);
		}
		// Matieres generales
		for (Matiere matiereGenerale : matieresGenerales) {
			if (!matieresClasse.contains(matiereGenerale))
				modeleMatieresGenerales.addMatiere(matiereGenerale);
		}

		// Contraindre la selection à une seule valeur à la fois
		matieresClasseList
				.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		matieresGeneralesList
				.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		// Modifier la taille des listes
		Dimension d = new Dimension(260, 180);
		matieresClasseScroll.setPreferredSize(d);
		matieresGeneralesScroll.setPreferredSize(d);
	}

	private void initComboBox() {
		/* Listeners */
		/* Combobox */
		// Liste des professeurs enseignants
		profEnseignantComboBox = new JComboBox();
		// Ajouter les enseignants
		profEnseignantComboBox.addItem("--Sélectionnez un enseignant--");

		/* Remplissage de la combobox */
		try {
			List<Enseignant> enseignants = controleur.getEnseignants();
			for (Enseignant enseignant : enseignants) {
				profEnseignantComboBox.addItem(enseignant);
			}
		} catch (HibernateException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
		// -----------------------------
		profEnseignantComboBox.setEnabled(false);
	}

	private void remplirClassePanel() {
		classePanel = new JPanel();
		classePanel.add(classeLabel);
		classePanel.add(classeTextField);
	}

	private void remplirValidationPanel() {
		validationPanel = new JPanel();
		validationPanel.add(validerButton);
	}

	private void remplirTitlePanel() {
		titlePanel = new JPanel();
		titlePanel.add(titleLabel);
	}

	private void remplirMiddlePanel() {
		middlePanel = new JPanel();
		GroupLayout gl = new GroupLayout(middlePanel);
		middlePanel.setLayout(gl);
		// Espacement des composants
		gl.setAutoCreateGaps(true);
		// Espacement entre composants et conteneur
		gl.setAutoCreateContainerGaps(true);

		// Groupe sequentiel sur l'axe horizontal
		GroupLayout.SequentialGroup hGroup = gl.createSequentialGroup();

		// Constitution des groupes paralleles horizontalement
		/* 1e colonne */
		hGroup.addGroup(gl.createParallelGroup()
				.addComponent(profEnseignantComboBox)
				.addComponent(ajouterMatiereButton)
				.addComponent(retirerMatiereButton));
		gl.setHorizontalGroup(hGroup);

		// Groupe sequentiel sur l'axe vertical
		GroupLayout.SequentialGroup vGroup = gl.createSequentialGroup();

		// Constitution des groupes paralleles verticalement
		/* 1e ligne */
		vGroup.addGroup(gl.createParallelGroup(Alignment.BASELINE)
				.addComponent(profEnseignantComboBox));
		/* 2e ligne */
		vGroup.addGroup(gl.createParallelGroup(Alignment.BASELINE)
				.addComponent(ajouterMatiereButton));
		/* 3e ligne */
		vGroup.addGroup(gl.createParallelGroup(Alignment.BASELINE)
				.addComponent(retirerMatiereButton));
		gl.setVerticalGroup(vGroup);
	}

	private void remplirMatiereClassePanel() {
		matieresClassePanel = new JPanel();
		GroupLayout gl = new GroupLayout(matieresClassePanel);
		matieresClassePanel.setLayout(gl);
		// Espacement des composants
		gl.setAutoCreateGaps(true);
		// Espacement entre composants et conteneur
		gl.setAutoCreateContainerGaps(true);

		// Groupe sequentiel sur l'axe horizontal
		GroupLayout.SequentialGroup hGroup = gl.createSequentialGroup();

		// Constitution des groupes paralleles horizontalement
		/* 1e colonne */
		hGroup.addGroup(gl.createParallelGroup()
				.addComponent(matieresClasseLabel)
				.addComponent(matieresClasseScroll));
		gl.setHorizontalGroup(hGroup);

		// Groupe sequentiel sur l'axe vertical
		GroupLayout.SequentialGroup vGroup = gl.createSequentialGroup();

		// Constitution des groupes paralleles verticalement
		/* 1e ligne */
		vGroup.addGroup(gl.createParallelGroup(Alignment.BASELINE)
				.addComponent(matieresClasseLabel));
		/* 2e ligne */
		vGroup.addGroup(gl.createParallelGroup(Alignment.BASELINE)
				.addComponent(matieresClasseScroll));
		gl.setVerticalGroup(vGroup);
	}

	private void remplirMatieresGeneralesPanel() {
		matieresGeneralesPanel = new JPanel();
		GroupLayout gl = new GroupLayout(matieresGeneralesPanel);
		matieresGeneralesPanel.setLayout(gl);
		// Espacement des composants
		gl.setAutoCreateGaps(true);
		// Espacement entre composants et conteneur
		gl.setAutoCreateContainerGaps(true);

		// Groupe sequentiel sur l'axe horizontal
		GroupLayout.SequentialGroup hGroup = gl.createSequentialGroup();

		// Constitution des groupes paralleles horizontalement
		/* 1e colonne */
		hGroup.addGroup(gl.createParallelGroup()
				.addComponent(matieresGeneralesLabel)
				.addComponent(matieresGeneralesScroll));
		gl.setHorizontalGroup(hGroup);

		// Groupe sequentiel sur l'axe vertical
		GroupLayout.SequentialGroup vGroup = gl.createSequentialGroup();

		// Constitution des groupes paralleles verticalement
		/* 1e ligne */
		vGroup.addGroup(gl.createParallelGroup(Alignment.BASELINE)
				.addComponent(matieresGeneralesLabel));
		/* 2e ligne */
		vGroup.addGroup(gl.createParallelGroup(Alignment.BASELINE)
				.addComponent(matieresGeneralesScroll));
		gl.setVerticalGroup(vGroup);
	}

	private void remplirCenterPanel() {
		centerPanel = new JPanel();
		centerPanel.add(matieresGeneralesPanel);
		centerPanel.add(middlePanel);
		centerPanel.add(matieresClassePanel);
	}

	private void remplirMainPanel() {
		mainPanel = new JPanel();
		mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
		mainPanel.add(classePanel);
		mainPanel.add(centerPanel);
		mainPanel.add(validationPanel);
	}

	/**
	 * Ferme la fenetre et libere les ressources
	 * 
	 */
	public void fermerVue() {
		this.setVisible(false);
		this.dispose();

	}

	/* Listeners */
	class AjouterMatiereButtonListener implements ActionListener {
		@Override
		public void actionPerformed(ActionEvent e) {
			if (profEnseignantComboBox.getSelectedIndex() != 0) {

				// Recuperation des modeles
				ModeleListeMatieres modeleMatieresGenerales = (ModeleListeMatieres) matieresGeneralesList
						.getModel();
				ModeleListeMatieres modeleMatieresClasse = (ModeleListeMatieres) matieresClasseList
						.getModel();
				// Recuperation des donnees
				Matiere nouvelleMatiereClasse = (Matiere) matieresGeneralesList
						.getSelectedValue();
				Enseignant enseignantClasse = (Enseignant) profEnseignantComboBox
						.getSelectedItem();

				// Mise à jour des listes
				modeleMatieresClasse.addMatiere((nouvelleMatiereClasse));
				modeleMatieresGenerales.removeMatiere(matieresGeneralesList
						.getSelectedIndex());
				// Mise à jour de la base
				Map<Matiere, Enseignant> matieresEnseignants = currentClasse
						.getEnseignantsResponsables();
				matieresEnseignants
						.put(nouvelleMatiereClasse, enseignantClasse);

			} else {
				Tools.displayError(
						"Vous devez d'abord selectionner un enseignant, ajout annulé",
						"Ajout de matiere annulé");
			}

		}
	}

	class RetirerMatiereButtonListener implements ActionListener {
		@Override
		public void actionPerformed(ActionEvent e) {
			// Recuperation des modeles
			ModeleListeMatieres modeleMatieresGenerales = (ModeleListeMatieres) matieresGeneralesList
					.getModel();
			ModeleListeMatieres modeleMatieresClasse = (ModeleListeMatieres) matieresClasseList
					.getModel();
			// Recuperation de la matiere
			Matiere matiereSupprimee = (Matiere) matieresClasseList
					.getSelectedValue();
			// Mise a jour des listes
			modeleMatieresGenerales.addMatiere(matiereSupprimee);
			modeleMatieresClasse.removeMatiere(matieresClasseList
					.getSelectedIndex());
			// Mise a jour de la base
			Map<Matiere, Enseignant> matieresEnseignants = currentClasse
					.getEnseignantsResponsables();
			matieresEnseignants.remove(matiereSupprimee);

		}

	}

	class ValiderButtonListener implements ActionListener {
		@Override
		public void actionPerformed(ActionEvent e) {
			vueActuelle.fermerVue();
		}

	}

	class MatieresGeneralesListListener implements ListSelectionListener {

		@Override
		public void valueChanged(ListSelectionEvent e) {
			if (!e.getValueIsAdjusting()) {

				if (matieresGeneralesList.getSelectedIndex() == -1) {
					// Aucune matiere selectionnee, masquer le bouton d'ajout
					ajouterMatiereButton.setEnabled(false);
					profEnseignantComboBox.setSelectedIndex(0);
					profEnseignantComboBox.setEnabled(false);

				} else {
					// Une matiere selectionnee, afficher le bouton d'ajout
					ajouterMatiereButton.setEnabled(true);
					profEnseignantComboBox.setEnabled(true);
				}
			}

		}

	}

	class MatieresClasseListListener implements ListSelectionListener {
		@Override
		public void valueChanged(ListSelectionEvent e) {
			if (!e.getValueIsAdjusting()) {

				if (matieresClasseList.getSelectedIndex() == -1) {
					// Aucune matiere selectionnee, masquer le bouton de retrait
					retirerMatiereButton.setEnabled(false);

				} else {
					// Une matiere selectionnee, afficher le bouton de retrait
					retirerMatiereButton.setEnabled(true);
				}
			}
		}

	}

	class QuitterDialogListener implements WindowListener {

		@Override
		public void windowActivated(WindowEvent e) {

		}

		@Override
		public void windowClosed(WindowEvent e) {

		}

		@Override
		public void windowClosing(WindowEvent e) {
			vueActuelle.fermerVue();
		}

		@Override
		public void windowDeactivated(WindowEvent e) {

		}

		@Override
		public void windowDeiconified(WindowEvent e) {
		}

		@Override
		public void windowIconified(WindowEvent e) {
		}

		@Override
		public void windowOpened(WindowEvent e) {

		}

	}

}
